﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AccelerateSensor.Database.InfluxDb;
using AccelerateSensor.Model.Node;
using AccelerateSensor.Service.Tools;
using InfluxNodeData = AccelerateSensor.Service.DbProxy.InfluxDb.Models.NodeData;

namespace AccelerateSensor.Service.DbProxy.InfluxDb
{
    internal class InfluxDbProxy
    {
        private readonly InfluxDbHelper _influxDbHelper;

        public InfluxDbProxy()
        {
            _influxDbHelper = new InfluxDbHelper(Constants.InfluxHost, Constants.Username, Constants.Password);
        }

        public void Init()
        {
            _influxDbHelper.Init(Constants.DatabaseName);
        }

        public void AddNodeData(NodeData nodeData)
        {
            var influxNodeData = GetInfluxNodeData(nodeData);
            _influxDbHelper.AddData(Constants.MeasurementName.NodeData, new[] { influxNodeData });
        }

        public async Task<int> GetNodeDataCountAsync(string nodeUuid)
        {
            var query = $"SELECT count(AcquireDataType) FROM {Constants.MeasurementName.NodeData} " +
                        $"WHERE NodeUuid = '{nodeUuid}'";
            return await _influxDbHelper.GetDataCountAsync(query);
        }

        public async Task<List<NodeData>> GetPageNodeDataAsync(
            string nodeUuid, int countPerPage, int curPage, int count)
        {
            var offset = countPerPage * (curPage - 1);
            var query = $"SELECT * FROM {Constants.MeasurementName.NodeData} " +
                        $"WHERE NodeUuid = '{nodeUuid}' " +
                        @"ORDER BY time DESC " +
                        $"LIMIT {count} OFFSET {offset}";
            var influxNodeDataList = await _influxDbHelper.GetDataAsync<InfluxNodeData>(query);
            return influxNodeDataList.Select(GetNodeData).ToList();
        }

        public async Task<List<NodeData>> GetNodeDataAsync(string nodeUuid, DateTime start, DateTime stop)
        {
            var query = $"SELECT * FROM {Constants.MeasurementName.NodeData} " +
                        $"WHERE NodeUuid = '{nodeUuid}' " +
                        $"AND time >= '{start:yyyy-MM-dd hh:mm:ss}' " +
                        $"AND time <= '{stop:yyyy-MM-dd hh:mm:ss}'";
            var influxNodeDataList = await _influxDbHelper.GetDataAsync<InfluxNodeData>(query);
            return influxNodeDataList.Select(GetNodeData).ToList();
        }

        #region Node Convert

        private static InfluxNodeData GetInfluxNodeData(NodeData nodeData)
        {
            var influxNodeData = new InfluxNodeData
            {
                Timestamp = nodeData.LocalUpdateTime,
                NodeUuid = nodeData.NodeUuid,
                AcquireDataType = nodeData.AcquireDataType,
                ChanNum = nodeData.ChanNum,
                SampleRate = nodeData.SampleRate,
                ChannelNames = string.Join(" ", nodeData.Names),
                UpdateTime = nodeData.UpdateTime
            };

            if (nodeData.ChanNum > 0)
            {
                influxNodeData.Ch0Values = string.Join(" ", nodeData.ValueList[0]);
            }

            if (nodeData.ChanNum > 1)
            {
                influxNodeData.Ch1Values = string.Join(" ", nodeData.ValueList[1]);
            }

            if (nodeData.ChanNum > 2)
            {
                influxNodeData.Ch2Values = string.Join(" ", nodeData.ValueList[2]);
            }

            return influxNodeData;
        }

        private static NodeData GetNodeData(InfluxNodeData influxNodeData)
        {
            var nodeData = new NodeData
            {
                NodeUuid = influxNodeData.NodeUuid,
                AcquireDataType = influxNodeData.AcquireDataType,
                ChanNum = influxNodeData.ChanNum,
                SampleRate = influxNodeData.SampleRate,
                Names = influxNodeData.ChannelNames.Split(' '),
                ValueList = new List<float[]>(),
                UpdateTime = influxNodeData.UpdateTime,
                LocalUpdateTime = influxNodeData.Timestamp
            };

            var ch0Values = influxNodeData.Ch0Values?.Split(' ')
                .Select(t => string.IsNullOrWhiteSpace(t) ? 0 : float.Parse(t)).ToArray();
            nodeData.ValueList.Add(ch0Values);

            var ch1Values = influxNodeData.Ch1Values?.Split(' ')
                .Select(t => string.IsNullOrWhiteSpace(t) ? 0 : float.Parse(t)).ToArray();
            nodeData.ValueList.Add(ch1Values);

            var ch2Values = influxNodeData.Ch2Values?.Split(' ')
                .Select(t => string.IsNullOrWhiteSpace(t) ? 0 : float.Parse(t)).ToArray();
            nodeData.ValueList.Add(ch2Values);

            return nodeData;
        }

        #endregion
    }
}
